/*
 * Copyright 2011 Angel Sanadinov
 *
 * This file is part of VBox WMI.
 *
 * VBox WMI is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * VBox WMI is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with VBox WMI.  If not, see <http://www.gnu.org/licenses/>.
 */

package Utilities;

import Utilities.Interfaces.CompressionResponseWrapper;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import Utilities.Constants.CompressionWrapperReturnedObject;

/**
 * A HTTP Servlet response wrapper for GZIP compression.
 *
 * @see GzipHttpServletOutputStream
 *
 * @author Angel Sanadinov
 */
public class GzipCompressionWrapper extends HttpServletResponseWrapper implements CompressionResponseWrapper
{
    private HttpServletResponse rawResponse;    //raw http servlet response
    private ServletOutputStream outputStream;   //compressed output stream
    private PrintWriter outputWriter;           //compressed print writer
    private CompressionWrapperReturnedObject returnedObject; //denotes which output object was returned

    /**
     * Constructs a new GZIP compression wrapper using the specified HTTP servlet response.
     *
     * @param response the servlet response
     * @throws IOException if an I/O error occurs
     */
    public GzipCompressionWrapper(HttpServletResponse response) throws IOException
    {
        super(response);
        this.rawResponse = response;
        this.outputStream = new GzipHttpServletOutputStream(rawResponse);
        this.outputWriter = null;
        this.returnedObject = CompressionWrapperReturnedObject.NONE;
    }

    /**
     * Commits the response to the client and closes the compressed stream.
     *
     * @throws IOException if an I/O error occurs
     */
    @Override
    public void commitResponse() throws IOException
    {
       if(outputWriter != null)
           outputWriter.close();
       else
           outputStream.close();
    }

    /**
     * Flushes the compressed stream.
     *
     * @throws IOException if an I/O error occurs
     */
    @Override
    public void flushBuffer() throws IOException
    {
        outputStream.flush();
    }

    /**
     * Retrieves the <code>PrintWriter</code> object associated with this response. <br><br>
     *
     * Only either a <code>PrintWriter</code> or an <code>OutputStream</code> can
     * be retrieved for a response.
     *
     * @return the requested object or throws an <code>IllegalStateException</code>
     *         if the output stream has already been retrieved
     * @throws IOException if an I/O error occurs
     *
     * @see GzipCompressionWrapper#getOutputStream() 
     */
    @Override
    public PrintWriter getWriter() throws IOException
    {
        PrintWriter result = null;

        switch(returnedObject)
        {
            //an object is yet to be retrieved for this response
            case NONE:
            {
                result = outputWriter = new PrintWriter(outputStream);
            } break;

            //the writer was requested before
            case WRITER:
                result = outputWriter; break;

            //the output stream was requested
            default:
                throw new IllegalStateException("getOutputStream() has already been called for this response");
        }

        returnedObject = CompressionWrapperReturnedObject.WRITER;
        return result;
    }

    /**
     * Retrieves the <code>OutputStream</code> object associated with this response. <br><br>
     *
     * Only either a <code>PrintWriter</code> or an <code>OutputStream</code> can
     * be retrieved for a response.
     *
     * @return the requested object or throws an <code>IllegalStateException</code>
     *         if the <code>PrintWriter</code> has already been retrieved
     * @throws IOException if an I/O error occurs
     */
    @Override
    public ServletOutputStream getOutputStream() throws IOException
    {
        ServletOutputStream result = null;

        switch(returnedObject)
        {
            //either no object was requested or the output stream was requested
            case NONE:
            case STREAM:
                result = outputStream; break;

            //the PrintWriter was requested
            default:
                throw new IllegalStateException("getWriter() has already been called for this response");
        }

        returnedObject = CompressionWrapperReturnedObject.STREAM;
        return result;
    }
}
